
#include "Enamerations/KeyboardButtons.h"

#include "EventSystem/MouseEvent.h"


#ifndef UTILS_WINDOW
#define UTILS_WINDOW

#include <string>

#include <iostream>

#include <functional>

#include <GLFW/glfw3.h>
#include <glad/glad.h>

class Window {
public:
    GLFWwindow* nativeWindow;
    std::string title;
    int width, height;

    bool isFirstInitilize = true;
    bool running = false;
    bool vSync = true;
    bool minimize = false;
    bool cursorFocusedEnable = false;

    std::function<void(Event&)> eventCallback;

    Window(
        const char* _title,
        const int   _width,
        const int   _height
    ) : title(_title), width(_width), height(_height) {
        if (isFirstInitilize) {
            if (!glfwInit()) {
                std::cout << "GLFW initialize failed!" << std::endl;
                return;
            }
            glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
            glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
            glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
        }
        nativeWindow = glfwCreateWindow(_width, _height, _title, NULL, NULL);
        glfwMakeContextCurrent(nativeWindow);

        if (isFirstInitilize) {
            if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
                std::cout << "GLAD initialize failed!" << std::endl;
                return;
            }
            isFirstInitilize = false;
        }

        glfwSwapInterval(1);
        glfwSetWindowUserPointer(nativeWindow, this);

        glfwSetErrorCallback([](int error_code, const char* description) {
            printf("GLFW Error[%d]: %s\n", error_code, description);
        });

        glfwSetCursorPosCallback(nativeWindow, [](GLFWwindow* window, double xpos, double ypos) {
            auto w = (Window*)glfwGetWindowUserPointer(window);
            auto event = MouseMoveEvent(xpos, ypos, MouseButton::None);
            w->eventCallback(event);
        });
    }
    ~Window() {
        glfwTerminate();
    }

    void swapBuffers() {
        glfwSwapBuffers(nativeWindow);
    }

    void pollEvents() {
        glfwPollEvents();
    }

    void setCursorFocusedEnable(const bool enable) {
        cursorFocusedEnable = enable;
        glfwSetInputMode(nativeWindow, GLFW_CURSOR, enable ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL);
    }

    bool isPressed(const KeyboardButton button) {
        int state = glfwGetKey(nativeWindow, (int)button);
        return state == GLFW_PRESS || state == GLFW_REPEAT;
    }

    bool isRunning() const {
        return !glfwWindowShouldClose(nativeWindow);
    }
};

#endif // UTILS_WINDOW
